/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.common;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.mina.common.IoSession;

import com.cqcis.uip.base.framework.UIPServiceException;
import com.cqcis.uip.base.framework.UIPTaskException;
import com.cqcis.uip.base.framework.common.impl.AttributesImpl;
import com.cqcis.uip.base.framework.utils.ByteBuffer;
import com.cqcis.uip.base.framework.utils.StringUtil;

/**
 * HTTP 参数
 * 
 * @author huangmy
 * @date 2008-12-4
 */
public class HttpParam extends AttributesImpl<Object> {
	private static final long serialVersionUID = 1L;
	public final static String CONSTRAIN_KEY_SEND = "CONSTRAIN_KEY_SEND_" + HttpParam.class.getName();
	public final static String CONSTRAIN_KEY_RECV = "CONSTRAIN_KEY_RECV_" + HttpParam.class.getName();
	public final static String STREAM_LOG_OUT_SERVICE = "STREAM_LOG_OUT_SERVICE_" + HttpParam.class.getName();
	
	public final static String PARAM_SPLIT = ": "; // 分割
	public final static String HTTP_SPLIT = "\r\n"; // 分行
	public final static String HEADER_ENCODE = "ISO-8859-1"; // 头部编码
	
	public final static String HTTP_RESP_OK = "HTTP/1.1 200 OK"; // 响应为OK
	
	public final static String TRANSFER_ENCODING = "Transfer-Encoding";
	public final static String CONTENT_LENGTH = "Content-length"; // body 长度
	public final static String CONNECTION = "Connection"; // 链接状态
	public final static String CONTENT_TYPE = "Content-Type"; // 内容类型
	public final static String DATE = "Date";
	public final static String SERVER = "Server";
	public final static String X_POWERED_BY = "X-Powered-By";
	
	public final static String CHUNKED = "chunked";
	public final static String POST = "POST";
	public final static String GET = "GET";

	private String headerline = HTTP_RESP_OK; // 响应行
	private Map<String, ParamContent> params = new LinkedHashMap<String, ParamContent>();
	private ByteBuffer contents = ByteBuffer.allocate(4).flip();
	private IoSession session; // SESSION
	private StatusLine statusLine;
	private ByteBuffer contentsPure = ByteBuffer.allocate(4).flip(); // PURE
	private String recordId; // for record DB log, null -> ignore
	
	public HttpParam() {
	}
	
	public HttpParam(String recordId) {
		if (!StringUtil.hasText(recordId)) {
			throw new UIPServiceException("param can't be null.");
		}
		this.recordId = recordId;
	}
	
	/**
	 * 获取返回值
	 * 
	 * @return
	 */
	public StatusLine getStatusLine() {
		if (this.statusLine != null) {
			return this.statusLine;
		}
		
		if (this.headerline != null && StatusLine.startsWithHTTP(this.headerline)) {
			this.statusLine = new StatusLine(this.headerline);
		}

		return this.statusLine;
	}

	/**
	 * 是否正确
	 * 
	 * @return
	 */
    public boolean isOK() {
    	StatusLine status = getStatusLine();
    	if (status == null) {
    		return false;
    	}
    	
    	return status.getStatusCode() == 200 ? true : false;
    }

	/**
	 * 获取返回头
	 * 
	 * @return
	 */
	public String getHeaderline() {
		return headerline;
	}
    
	/**
	 * 设置返回头
	 * 
	 * @param responseHeaderline
	 */
	public void setHeaderline(String headerline) {
		this.headerline = headerline;
	}

	/**
	 * 所有
	 * 
	 * @return
	 */
	public Map<String, ParamContent> getParams() {
		return params;
	}

	/**
	 * 添加
	 * 
	 * @param param
	 */
	public void addParams(ParamContent param) {
		this.params.put(param.name, param);
	}
	
	/**
	 * 添加
	 * 
	 * @param name
	 * @param value
	 */
	public void addParams(String name, String value) {
		this.addParams(new ParamContent(name, value));
	}
	
	/**
	 * 添加所有
	 * 
	 * @param params
	 */
	public void addAllParams(Collection<ParamContent> params) {
		if (params == null) {
			return;
		}
		
		for (ParamContent param : params) {
			addParams(param);
		}
	}
	
	/**
	 * 获取
	 * 
	 * @param name
	 * @return
	 */
	public ParamContent getParam(String name) {
		return this.params.get(name);
	}
	
	/**
	 * 删除
	 * 
	 * @param name
	 * @return
	 */
	public ParamContent removeParam(String name) {
		return this.params.remove(name);
	}

	/**
	 * 获取
	 * 
	 * @return
	 */
	public ByteBuffer getContents() {
		return contents;
	}
	
	/**
	 * PURE
	 * 
	 * @return
	 */
	public ByteBuffer getPureContents() {
		return contentsPure;
	}
	
	/**
	 * 获取 stream
	 * 
	 * @return
	 */
	public InputStream getContentsAsStream() {
		return new ByteArrayInputStream(getPureContents().getPrintArray());
	}

	/**
	 * 设置
	 * 
	 * @param contents
	 */
	public void setContents(ByteBuffer contents) {
		if (contents == null) {
			return;
		}
		int oldpos = contents.position();
		int oldlimit = contents.limit();
		this.contents = ByteBuffer.allocate(1024).setAutoExpand(true);
		this.contents.put(contents); 
		this.contents.flip();
		contents.position(oldpos);
		contents.limit(oldlimit);
		this.contentsPure = ByteBuffer.allocate(1024).setAutoExpand(true);
		this.contentsPure.put(contents);
		this.contentsPure.flip();
	}
	
	@Override
	public String toString() {		
		try {
			ByteBuffer buf = buf();
			return new String(buf.getPrintArray(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			return e.getMessage();
		}
	}
	
	/**
	 * 头部
	 * 
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public ByteBuffer getHeaders() throws UnsupportedEncodingException {
        ByteBuffer buffer = ByteBuffer.allocate(1024).setAutoExpand(true);
		
		buffer.put(getHeaderline().getBytes(HEADER_ENCODE));
		buffer.put(HTTP_SPLIT.getBytes(HEADER_ENCODE));
		
		boolean contentLenthAdd = false;
		for (String key : getParams().keySet()) {
			String name = key.toLowerCase();
			String value = getParams().get(key).getValue();
			if (name.indexOf(HttpParam.CONTENT_LENGTH.toLowerCase()) >= 0
					|| (name.indexOf(HttpParam.TRANSFER_ENCODING.toLowerCase()) >= 0 
							&& CHUNKED.equalsIgnoreCase(value))) {// 长度
				contentLenthAdd = true;
				break;
			}
		}
		
		if (!contentLenthAdd) {
			getParams().put(CONTENT_LENGTH, new ParamContent(CONTENT_LENGTH, 
					String.valueOf(getPureContents().limit())));
		}
		
		for (ParamContent p : getParams().values()) {
			buffer.put(p.format().getBytes(HEADER_ENCODE));
			buffer.put(HTTP_SPLIT.getBytes(HEADER_ENCODE));
		}
				
		buffer.put(HTTP_SPLIT.getBytes(HEADER_ENCODE));	
		
        buffer.flip();
		
		return buffer;
	}
	
	/**
	 * 头部信息
	 * 
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String getHeadersString() {
		ByteBuffer buf = null;
		try {
			buf = getHeaders();
			return new String(buf.array(), HEADER_ENCODE);
		} catch (UnsupportedEncodingException e) {
			throw new UIPTaskException(e);
		}
	}
	
	/**
	 * 转换为buffer
	 * 
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public ByteBuffer buf() throws UnsupportedEncodingException {
		ByteBuffer buffer = ByteBuffer.allocate(1024).setAutoExpand(true);
		
		buffer.put(getHeaders());	
		buffer.put(getPureContents().getPrintArray());
		buffer.flip();
		
		return buffer;
	}
	
	/**
	 * session
	 * 
	 * @return
	 */
	public IoSession getSession() {
		return session;
	}

	/**
	 * 设置关联session
	 * 
	 * @param session
	 */
	public void setSession(IoSession session) {
		if (session == null) {
			throw new UIPServiceException("session can't be null.");
		}
		this.session = session;
		
		String constrainKey = StringUtil.hasText(this.recordId) ? CONSTRAIN_KEY_SEND : CONSTRAIN_KEY_RECV;
		if (this.session.containsAttribute(constrainKey) && constrainKey.equalsIgnoreCase(CONSTRAIN_KEY_RECV)) {
			constrainKey = CONSTRAIN_KEY_SEND;
		}
		this.session.setAttribute(constrainKey, this);
	}
	
	public static class ParamContent {
		private String name;
		private String value;

		public ParamContent(String name, String value) {
			this.name = name;
			this.value = value;
		}

		public String format() {
			if (StringUtil.hasText(this.name)) {
				return this.name + PARAM_SPLIT + this.value;
			}

			return null;
		}

		@Override
		public String toString() {
			return format();
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}
	}

	public String getRecordId() {
		return recordId;
	}
}
